package org.totoro.lambda;

import org.junit.Before;
import org.junit.Test;
import org.totoro.Users;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author yhl
 * @Description:
 * @date：2017/10/13 0013
 * @tiem：9:51
 */

public class StreamTest {

    private List<String> list = new ArrayList<>();

    List<Users> users;

    @Before
    public void load() {
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("赵六");

        users = Arrays.asList(new Users(1, "张三", 18),
                new Users(2, "李四", 30),
                new Users(3, "王五", 20),
                new Users(4, "赵六", 18));

    }

    /**
     * 过滤集合中的元素
     *
     * @see Stream#filter(Predicate)
     * <p>
     * 把过滤出的元素，放到新集合中去
     * @see Stream#collect(Collector)
     */
    @Test
    public void filter() {
        list.stream().filter(item -> {
            return !"张三".equals(item);
        }).collect(Collectors.toList()).forEach(item -> System.out.println(item));

    }

    /**
     * 循环集合中所有的元素，然后把修改后的值，覆盖当前循环的值
     *
     * @see Stream#map(Function)
     * @see Stream#mapToDouble(ToDoubleFunction)
     * @see Stream#mapToInt(ToIntFunction)
     * @see Stream#mapToLong(ToLongFunction)
     */

    @Test
    public void map() {
        list.stream().map(item -> item + ";").collect(Collectors.toList()).forEach(item -> System.out.println(item));

    }

    /**
     * 把多个  Stream 合并成一个  Stream
     *
     * @see Stream#flatMap(Function)
     * @see Stream#flatMapToDouble(Function)
     * @see Stream#flatMapToInt(Function)
     * @see Stream#flatMapToLong(Function)
     */
    @Test
    public void flatMap() {

        List<Integer> together = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4)).flatMap(numbers -> numbers.stream()).collect(Collectors.toList());

        together.forEach(item -> {
            System.out.println(item);
        });


    }

    /**
     * 去重
     *
     * @see Stream#distinct()
     */
    @Test
    public void distinct() {

        Arrays.asList(1, 2, 3, 1, 4).stream().distinct().forEach(item -> {
            System.out.println(item);
        });

    }


    /**
     * 排序
     *
     * @see Stream#sorted()
     */
    @Test
    public void sorted() {

        Arrays.asList(4, 1, 5, 3, 2, 8, 9, 0).stream().sorted((o1, o2) -> {
            return o1.compareTo(o2);
        }).forEach(item -> System.out.println(item));


        Arrays.asList(4, 1, 5, 3, 2, 8, 9, 0).stream().sorted(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        }).forEach(item -> System.out.println(item));

    }


    /**
     * peek 类似于懒加载，当你用到你 peek 方法中的元素时才会执行 peek 方法中的具体逻辑
     * <p>
     * <p>
     * 网上的解释 ：生成一个包含原Stream的所有元素的新Stream (这句话有误导) ，同时会提供一个消费函数（Consumer实例），新Stream每个元素被消费的时候都会执行给定的消费函数；
     */
    @Test
    public void peek() {

        Stream.of("one", "two", "three", "four")
                .filter(e -> e.length() > 3)
                .peek(e -> System.out.println("Filtered value: " + e))
                .map(String::toUpperCase)
                .peek(e -> System.out.println("Mapped value: " + e))
                .collect(Collectors.toList());


        list.stream().filter(item -> {
            return !"张三".equals(item);
        }).peek(item -> {
            System.out.println(item);
        }).collect(Collectors.toList());

    }

    /**
     * 截断
     */
    @Test
    public void limit() {

        list.stream().limit(2).forEach(item -> {
            System.out.println(item);
        });
    }

    /**
     * 跳过元素
     * <p>
     * 配合 limit 达到分页效果
     */
    @Test
    public void skip() {

        list.stream().skip(1).forEach(System.out::println);

        /**
         * 分页效果
         */
        System.out.println("----------------------");
        list.stream().skip(1).limit(2).forEach(item -> {
            System.out.println(item);
        });
    }


    /**
     * 主要是做计算
     * <p>
     * 参考：http://blog.csdn.net/io_field/article/details/54971679
     */
    @Test
    public void reduce() {

        /**
         * old 上次处理结果
         * next 下一个循环的对象
         * return 返回结果，是下一次reduce的 old
         *
         * 找出最大值
         *
         */
        Optional<Users> reduce = users.stream().reduce((old, next) -> {

            int i = old.getAge().compareTo(next.getAge());

            if (i == 1) {
                return old;
            } else {
                return next;
            }
        });

        Users user = reduce.get();

        System.out.println(user);

    }

    /**
     * 有匹配的元素返回 true
     */
    public void allMatch() {

        boolean b = users.stream().allMatch((e -> {
            return e.getAge() > 5;
        }));

    }


    /**
     * 没有  配置的元素  返回 ture
     */
    public void anyMatch() {

        boolean b = users.stream().anyMatch((e -> {
            return e.getAge() > 5;
        }));

    }


    /**
     * findAny能够从流中随便选一个元素出来，它返回一个Optional类型的元素。
     * <p>
     * isPresent()
     * 判断容器中是否有值。
     * <p>
     * ifPresent(Consume lambda)
     * 容器若不为空则执行括号中的Lambda表达式。
     * <p>
     * T get()
     * 获取容器中的元素，若容器为空则抛出NoSuchElement异常。
     * <p>
     * T orElse(T other)
     * 获取容器中的元素，若容器为空则返回括号中的默认值。
     */
    public void findAny() {
        Optional<Users> any = users.stream().findAny();
    }

    /**
     * 获取第一个元素findFirst
     */
    public void findFirst() {
        Optional<Users> first = users.stream().findFirst();
    }


}
